feat(NumberTheory/Bernoulli): von Staudt-Clausen theorem#34906
feat(NumberTheory/Bernoulli): von Staudt-Clausen theorem#34906seewoo5 wants to merge 64 commits intoleanprover-community:masterfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n section - Remove unused `Units.val_mk` from simp calls - Convert deprecated `induction'` to `induction` in three lemmas - Fix whitespace: `2*m` → `2 * m`, `2*k` → `2 * k`, `)^(` → `) ^ (` - Fix resulting lines exceeding 100 char limit - Add `set_option linter.style.longFile 1800` for file length Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify several proofs by inlining single-use haves, using pow_succ, removing redundant intermediate steps, and leveraging Finset.sum_filter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…a proofs Remove `have IH := IH` identity bindings, unwrap redundant `have h1 := ...; exact h1` wrapping, inline single-use omega equalities into pow_succ rewrites, and merge consecutive single-use rewrite steps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…o callers Merge trivial single-use helper lemmas directly into their sole call sites to reduce declaration count and improve code locality. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Golf 4 verbose proofs by replacing manual have-chains with field_simp/ring, leveraging core_algebraic_identity, and eliminating redundant cast round-trips. Net savings: ~130 lines. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…callers Remove lemmas with 1-2 line proof bodies that are used only once or not at all, inlining their proofs at call sites to reduce indirection. Dead code removed: pIntegral_add, pIntegral_even_term Inlined: geom_sum_of_root_of_unity, generator_pow_card_sub_one_eq_one, pIntegral_neg_pow_div_two, pIntegral_odd_term, power_sum_eq_faulhaber, coprime_add_of_coprime_den, von_staudt_clausen_pos Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d_rest Replace ~120-line proof with ~15-line proof using by_cases on divisibility, Finset.add_sum_erase for the positive case, and Finset.filter_congr for the negative case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR summary ee3a5404e5Import changes exceeding 2%
|
| File | Base Count | Head Count | Change |
|---|---|---|---|
| Mathlib.NumberTheory.Bernoulli | 1639 | 2056 | +417 (+25.44%) |
Import changes for all files
| Files | Import difference |
|---|---|
8 filesMathlib.NumberTheory.ModularForms.DedekindEta Mathlib.NumberTheory.ModularForms.Delta Mathlib.NumberTheory.ModularForms.Derivative Mathlib.NumberTheory.ModularForms.Discriminant Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.MDifferentiable Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Summable Mathlib.NumberTheory.ModularForms.EisensteinSeries.E2.Transform Mathlib.NumberTheory.ModularForms.EisensteinSeries.QExpansion |
6 |
Mathlib.NumberTheory.LSeries.HurwitzZetaValues |
78 |
Mathlib.NumberTheory.ZetaValues |
79 |
Mathlib.NumberTheory.BernoulliPolynomials |
415 |
Mathlib.NumberTheory.Bernoulli |
417 |
Declarations diff
+ bernoulli_add_indicator_den_not_dvd
+ bernoulli_add_indicator_eq_sub
+ choose_two_mul_succ_mul_div_eq
+ den_sum_dvd_prod_den
+ exists_int_sum_pow_add_indicator_eq
+ factorization_succ_le_sub_one
+ faulhaber_sum_div_prime_eq
+ pIntegral
+ pIntegral_bernoulli_even_term
+ pIntegral_bernoulli_one_term
+ pIntegral_choose_mul_pow_div
+ pIntegral_faulhaber_sum
+ pIntegral_mul
+ pIntegral_pow_div
+ prod_one_div_prime_den_coprime
+ sum_one_div_prime_eq_indicator_div_add
+ sum_pow_add_indicator_eq_zero
+ sum_pow_filter_eq_faulhaber
+ vonStaudtIndicator
+ vonStaudtPrimes
+ vonStaudt_clausen
+ vonStaudt_sum_den_not_dvd
You can run this locally as follows
## summary with just the declaration names:
./scripts/pr_summary/declarations_diff.sh <optional_commit>
## more verbose report:
./scripts/pr_summary/declarations_diff.sh long <optional_commit>The doc-module for scripts/pr_summary/declarations_diff.sh contains some details about this script.
No changes to technical debt.
This script lives in the mathlib-ci repository. To run it locally, from your mathlib4 directory:
git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci
../mathlib-ci/scripts/reporting/technical-debt-metrics.sh pr_summary
- The
relativevalue is the weighted sum of the differences with weight given by the inverse of the current value of the statistic. - The
absolutevalue is therelativevalue divided by the total sum of the inverses of the current values (i.e. the weighted average of the differences).
Add missing documentation for `vonStaudtIndicator` and `pIntegral`. Remove unused arguments from `cast_ne_zero_of_mem_filter`, `generator_pow_ne_one`, `sum_units_pow_eq_zero_of_not_dvd`, `den_pow_div_dvd`, `valuation_bound`, `pIntegral_pow_div_factor`, and `pIntegral_T1`, along with their call sites. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused arguments from pIntegral_T2, pIntegral_case_one, even_term_decomposition_identity, power_sum_indicator_divisible_by_p, divisibility_to_rat_eq, sum_other_primes_coprime_p_pos, and cascading unused arguments in pIntegral_second_term, pIntegral_coeff_term, pIntegral_first_term, and pIntegral_even_term_in_sum. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ther Move pIntegral_of_int, pIntegral_mul, pIntegral_mul_int, pIntegral_mul_nat, and pIntegral_sub to directly after pIntegral_sum so all basic pIntegral closure properties are co-located. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove pIntegral_nat_mul and use pIntegral_int_mul directly at call sites, relying on Lean's automatic ℕ → ℤ coercion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge the single-use von_staudt_clausen_zero lemma directly into the k = 0 case of von_staudt_clausen. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove single-use i1_term_forms_eq and replace it with a shorter `convert` + `push_cast` + `field_simp` proof inside pIntegral_i1_term_in_sum. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Inline ~20 single-use helper lemmas into their callers, reducing the file from ~1053 to 884 lines and from ~80 to 60 definitions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| Rado's proof is based on Faulhaber's theorem and induction on $k$. | ||
| -/ | ||
|
|
||
| namespace bernoulli |
There was a problem hiding this comment.
| namespace bernoulli | |
| namespace Bernoulli |
Lower-case namespace names are rare in Mathlib ('namespace [a-z].' occurs 414 times, 'namespace [A-Z].' 13461 times). I don't think there is official guidance regarding this point, but my feeling is that Bernoulli fits better with established patterns.
|
|
||
| /- Over `ZMod p`, the nonzero `l`-th power sum equals the negative indicator of `(p - 1) ∣ l`. -/ | ||
| private lemma sum_pow_add_indicator_eq_zero (p l : ℕ) [Fact p.Prime] : | ||
| (∑ v ∈ Finset.range p with v ≠ 0, (v : ZMod p) ^ l) + |
There was a problem hiding this comment.
Why not usse v ∈ Ico 1 p?
(Moving this; the line numbers had changed.)
| private lemma den_sum_dvd_prod_den {ι : Type*} (s : Finset ι) (f : ι → ℚ) : | ||
| (∑ i ∈ s, f i).den ∣ ∏ i ∈ s, (f i).den := by |
There was a problem hiding this comment.
This would make sense as an API lemma on rational numbers (so I suggest to make it public and move it to a file dealing with basic properties of rational numbers).
In fact, it would be good to also have
- the stronger result with
s.lcm (fun i \map (f i).den)on the right, - the corresponding result for products.
| rw [Finset.sum_insert has, Finset.prod_insert has] | ||
| exact (Rat.add_den_dvd _ _).trans (mul_dvd_mul_left _ ih) | ||
|
|
||
| private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) |
There was a problem hiding this comment.
| private lemma pIntegral_mul (p : ℕ) [Fact p.Prime] (x y : ℚ) | |
| private lemma pIntegral_mul {p : ℕ} [Fact p.Prime] {x y : ℚ} |
hx and hy determine p, x and y.
| rw [bernoulli_one] | ||
| obtain rfl | hp2 := eq_or_ne p 2 | ||
| · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = | ||
| -(2 : ℤ) ^ (2 * k - 2) := by | ||
| rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp | ||
| simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) | ||
| · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity | ||
| have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = | ||
| (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by | ||
| field_simp [hk_ne]; push_cast; ring | ||
| rw [hrw] | ||
| exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p (-1)) | ||
| (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by | ||
| rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by | ||
| have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] | ||
| exact Nat.zero_le _)) |
There was a problem hiding this comment.
| rw [bernoulli_one] | |
| obtain rfl | hp2 := eq_or_ne p 2 | |
| · have h : ((-1 / 2 : ℚ) * (2 * k) * (2 : ℚ) ^ (2 * k - 1) / (2 * k)) = | |
| -(2 : ℤ) ^ (2 * k - 2) := by | |
| rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp | |
| simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) | |
| · have hk_ne : (2 * k : ℚ) ≠ 0 := by positivity | |
| have hrw : (-1 / 2 : ℚ) * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k) = | |
| (-1 : ℤ) * ((p : ℚ) ^ (2 * k - 1) / 2) := by | |
| field_simp [hk_ne]; push_cast; ring | |
| rw [hrw] | |
| exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p (-1)) | |
| (pIntegral_pow_div p 2 (2 * k - 1) two_ne_zero (by | |
| rw [Nat.factorization_eq_zero_of_not_dvd (fun h ↦ by | |
| have := Nat.le_of_dvd two_pos h; have := (Fact.out : p.Prime).two_le; lia)] | |
| exact Nat.zero_le _)) | |
| field_simp | |
| rw [bernoulli_one] | |
| obtain rfl | hp2 := eq_or_ne p 2 | |
| · have h : ((-1 / 2 : ℚ) * (2 : ℚ) ^ (2 * k - 1)) = -(2 : ℤ) ^ (2 * k - 2) := by | |
| rw [(by lia : 2 * k - 1 = (2 * k - 2) + 1), pow_succ]; push_cast; field_simp | |
| simpa [h] using Int.padicValuation_le_one _ (-(2 : ℤ) ^ (2 * k - 2)) | |
| · refine pIntegral_mul p _ _ ?_ ?_ <;> rw [pIntegral, Rat.padicValuation_le_one_iff] | |
| · norm_num | |
| simpa [Nat.prime_dvd_prime_iff_eq Fact.out Nat.prime_two] | |
| · simp [show p ≠ 1 from Nat.Prime.ne_one Fact.out] |
You'll need to import Mathlib.Tactic.NormNum.GCD for the norm_num to work.
| have h : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = | ||
| ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by | ||
| have hm_le : 2 * m ≤ 2 * k + 1 := by lia | ||
| rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] | ||
| conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] | ||
| push_cast [Nat.cast_sub hm_le]; ring | ||
| rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, | ||
| mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] |
There was a problem hiding this comment.
| have h : ((2 * k + 1).choose (2 * m) : ℚ) / (2 * k + 1) = | |
| ((2 * k).choose (2 * m) : ℚ) / (2 * k - 2 * m + 1) := by | |
| have hm_le : 2 * m ≤ 2 * k + 1 := by lia | |
| rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia)] | |
| conv_rhs => norm_cast; rw [Nat.choose_mul_succ_eq] | |
| push_cast [Nat.cast_sub hm_le]; ring | |
| rw [mul_comm ((2 * k + 1).choose (2 * m) : ℚ) x, mul_div_assoc, | |
| mul_comm ((2 * k).choose (2 * m) : ℚ) x, mul_div_assoc, h] | |
| rw [div_eq_div_iff (by norm_cast) (by norm_cast; lia), mul_right_comm _ x, mul_right_comm _ x] | |
| refine congrArg (· * x) ?_ | |
| rw [show (2 * (k : ℚ) - 2 * (m : ℚ) + 1) = (↑(2 * k + 1 - 2 * m) : ℚ) by norm_cast; lia] | |
| exact_mod_cast Nat.choose_mul_succ_eq (2 * k) (2 * m) |>.symm |
| have h_denom_rat : (2 * (k : ℚ) - 2 * m + 1) = ((d + 1 : ℕ) : ℚ) := by | ||
| simp only [hd_def]; push_cast [Nat.cast_sub hkm]; ring | ||
| rw [h_exp, h_denom_rat, mul_div_assoc] | ||
| exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) |
There was a problem hiding this comment.
| exact pIntegral_mul p _ _ (by exact_mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) | |
| exact pIntegral_mul p _ _ (mod_cast Int.padicValuation_le_one p ((2 * k).choose (2 * m))) |
| (ih : pIntegral p (bernoulli (2 * m) + vonStaudtIndicator (2 * m) p / p)) : | ||
| pIntegral p (bernoulli (2 * m) * ((2 * k + 1).choose (2 * m)) * | ||
| (p : ℚ) ^ (2 * k - 2 * m) / (2 * k + 1)) := by | ||
| have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) |
There was a problem hiding this comment.
| have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Nat.Prime.ne_zero Fact.out) | |
| have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Nat.Prime.ne_zero Fact.out) |
| pIntegral p (((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m - 1) / | ||
| (2 * k - 2 * m + 1)) := by |
There was a problem hiding this comment.
If you prove here
pIntegral p (↑((2 * k + 1).choose (2 * m)) * ↑p ^ (2 * k - 2 * m) / (2 * ↑k + 1))
instead, then you can simplify the proof of pIntegral_bernoulli_even_term below (from around line 590). It looks like this is the only place where this lemma is used.
OK, maybe not -- it is used twice in the proof below...
| apply (Rat.padicValuation p).map_sub_le | ||
| · rw [mul_assoc, mul_div_assoc] | ||
| apply pIntegral_mul _ _ _ ih | ||
| have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / | ||
| (2 * k - 2 * m + 1) = | ||
| (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by | ||
| rw [hpow]; ring | ||
| rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, hpow_mul] | ||
| exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp | ||
| · unfold vonStaudtIndicator; split_ifs | ||
| · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp | ||
| · simp only [zero_mul, zero_div, map_zero]; exact bot_le |
There was a problem hiding this comment.
| apply (Rat.padicValuation p).map_sub_le | |
| · rw [mul_assoc, mul_div_assoc] | |
| apply pIntegral_mul _ _ _ ih | |
| have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / | |
| (2 * k - 2 * m + 1) = | |
| (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by | |
| rw [hpow]; ring | |
| rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt, hpow_mul] | |
| exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp | |
| · unfold vonStaudtIndicator; split_ifs | |
| · simp only [one_mul]; rw [choose_two_mul_succ_mul_div_eq k m _ hm_lt]; exact hcmp | |
| · simp only [zero_mul, zero_div, map_zero]; exact bot_le | |
| have H x := choose_two_mul_succ_mul_div_eq k m x hm_lt | |
| apply (Rat.padicValuation p).map_sub_le | |
| · rw [mul_assoc, mul_div_assoc] | |
| apply pIntegral_mul _ _ _ ih | |
| have hpow_mul : ((2 * k).choose (2 * m) : ℚ) * (p : ℚ) ^ (2 * k - 2 * m) / | |
| (2 * k - 2 * m + 1) = | |
| (p : ℚ) * (((2 * k).choose (2 * m) : ℚ) * P / (2 * k - 2 * m + 1)) := by | |
| rw [hpow]; ring | |
| rw [H, hpow_mul] | |
| exact pIntegral_mul _ _ _ (Int.padicValuation_le_one p p) hcmp | |
| · unfold vonStaudtIndicator | |
| split_ifs | |
| · grind | |
| · simp |
| apply (Rat.padicValuation p).map_sum_le | ||
| intro i hi |
There was a problem hiding this comment.
| apply (Rat.padicValuation p).map_sum_le | |
| intro i hi | |
| refine (Rat.padicValuation p).map_sum_le fun i hi ↦ ? |
| (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp | ||
| _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 | ||
| _ ≤ p ^ (2 * k) := Nat.pow_le_pow_left (Fact.out : p.Prime).two_le _) |
There was a problem hiding this comment.
| (Nat.factorization_le_of_le_pow <| calc 2 * k + 1 = (2 * k + 1).choose 1 := by simp | |
| _ ≤ 2 ^ (2 * k) := Nat.choose_succ_le_two_pow _ 1 | |
| _ ≤ p ^ (2 * k) := Nat.pow_le_pow_left (Fact.out : p.Prime).two_le _) | |
| (factorization_succ_le_sub_one p (2 * k) (by lia) |>.trans tsub_le_self) |
since you have factorization_succ_le_sub_one already...
| private lemma pIntegral_bernoulli_one_term (k p : ℕ) (hk : k > 0) [Fact p.Prime] : | ||
| pIntegral p (bernoulli 1 * (2 * k) * (p : ℚ) ^ (2 * k - 1) / (2 * k)) := by |
There was a problem hiding this comment.
The (I think only) use case is
(Rat.padicValuation p) (bernoulli 1 * ↑(2 * k + 1) * ↑p ^ (2 * k - 1) / (2 * ↑k + 1)) ≤ 1.
So it would make sense to prove that instead. (The proof suggested below works also for this version.)
| · simp only [bernoulli_eq_zero_of_odd hodd (by lia), | ||
| zero_mul, zero_div, map_zero]; exact bot_le |
There was a problem hiding this comment.
| · simp only [bernoulli_eq_zero_of_odd hodd (by lia), | |
| zero_mul, zero_div, map_zero]; exact bot_le | |
| · simp [bernoulli_eq_zero_of_odd hodd (by lia)] |
| (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by | ||
| push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) |
There was a problem hiding this comment.
| (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := by | |
| push_cast; exact sum_pow_add_indicator_eq_zero p (2 * k) | |
| (if (p - 1) ∣ 2 * k then 1 else 0)) : ZMod p) = 0 := | |
| mod_cast sum_pow_add_indicator_eq_zero p (2 * k) |
| rw [show vonStaudtIndicator (2 * k) p = ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) by | ||
| unfold vonStaudtIndicator; split_ifs <;> simp] |
There was a problem hiding this comment.
| rw [show vonStaudtIndicator (2 * k) p = ((if (p - 1) ∣ 2 * k then (1 : ℤ) else 0) : ℚ) by | |
| unfold vonStaudtIndicator; split_ifs <;> simp] | |
| unfold vonStaudtIndicator |
| (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1)) + p * bernoulli (2 * k) := by | ||
| have hfilter : (∑ v ∈ Finset.range p with v ≠ 0, (v : ℚ) ^ (2 * k)) = | ||
| ∑ v ∈ Finset.range p, (v : ℚ) ^ (2 * k) := | ||
| Finset.sum_filter_of_ne fun v _ hne ↦ by rintro rfl; exact hne (by simp [(by lia : 2 * k ≠ 0)]) |
There was a problem hiding this comment.
| Finset.sum_filter_of_ne fun v _ hne ↦ by rintro rfl; exact hne (by simp [(by lia : 2 * k ≠ 0)]) | |
| Finset.sum_filter_of_ne fun v _ hne ↦ ne_zero_pow (by lia) (mod_cast hne) |
| have hne : (2 * k + 1 : ℚ) ≠ 0 := by positivity | ||
| rw [hfilter, sum_range_pow, Finset.sum_range_succ] | ||
| push_cast | ||
| congr 1 | ||
| rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia, pow_one] | ||
| push_cast; field_simp [hne] |
There was a problem hiding this comment.
| have hne : (2 * k + 1 : ℚ) ≠ 0 := by positivity | |
| rw [hfilter, sum_range_pow, Finset.sum_range_succ] | |
| push_cast | |
| congr 1 | |
| rw [Nat.choose_succ_self_right, show 2 * k + 1 - 2 * k = 1 by lia, pow_one] | |
| push_cast; field_simp [hne] | |
| rw [hfilter, sum_range_pow, Finset.sum_range_succ, Nat.choose_succ_self_right, | |
| show 2 * k + 1 - 2 * k = 1 by lia] | |
| push_cast | |
| field_simp |
| (p : ℚ) ^ (2 * k + 1 - i) / (2 * k + 1 : ℚ)) / (p : ℚ) = | ||
| ∑ i ∈ Finset.range (2 * k), bernoulli i * ((2 * k + 1).choose i : ℚ) * | ||
| (p : ℚ) ^ (2 * k - i) / (2 * k + 1 : ℚ) := by | ||
| have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero |
There was a problem hiding this comment.
| have hp_ne : (p : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (Fact.out : p.Prime).ne_zero | |
| have hp_ne : (p : ℚ) ≠ 0 := mod_cast (Fact.out : p.Prime).ne_zero |
etc.; this occurs several times.
| rw [hAlg]; congr 1; simpa using faulhaber_sum_div_prime_eq k p | ||
|
|
||
| /- For fixed prime `p`, the denominator of `B_{2k} + e_{2k}(p)/p` is not divisible by `p`. -/ | ||
| private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : |
There was a problem hiding this comment.
| private lemma bernoulli_add_indicator_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : | |
| private lemma not_dvd_den_bernoulli_add_indicator (k p : ℕ) (hk : k > 0) [Fact p.Prime] : |
| exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) | ||
|
|
||
| /- Extends the fixed-prime nondivisibility result to the full prime correction sum. -/ | ||
| private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : |
There was a problem hiding this comment.
| private lemma vonStaudt_sum_den_not_dvd (k p : ℕ) (hk : k > 0) [Fact p.Prime] : | |
| private lemma not_dvd_den_vonStaudt_sum (k p : ℕ) (hk : k > 0) [Fact p.Prime] : |
(The lemmas are private, so the names don't matter too much, but it is still good practice to follow the naming convention.)
| have hT_int : pIntegral p (T : ℚ) := Int.padicValuation_le_one p T | ||
| have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), | ||
| bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by | ||
| apply pIntegral_faulhaber_sum k p hk | ||
| intro m hm_pos hm_lt | ||
| exact Rat.padicValuation_le_one_iff.2 (ih m hm_lt hm_pos) | ||
| exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) |
There was a problem hiding this comment.
| have hT_int : pIntegral p (T : ℚ) := Int.padicValuation_le_one p T | |
| have hR : pIntegral p (∑ i ∈ Finset.range (2 * k), | |
| bernoulli i * ((2 * k + 1).choose i) * (p : ℚ) ^ (2 * k - i) / (2 * k + 1)) := by | |
| apply pIntegral_faulhaber_sum k p hk | |
| intro m hm_pos hm_lt | |
| exact Rat.padicValuation_le_one_iff.2 (ih m hm_lt hm_pos) | |
| exact Rat.padicValuation_le_one_iff.1 ((Rat.padicValuation p).map_sub_le hT_int hR) | |
| have hT_int : pIntegral p T := Int.padicValuation_le_one p T | |
| have hR := pIntegral_faulhaber_sum k p hk fun m hm_pos hm_lt ↦ | |
| Rat.padicValuation_le_one_iff.mpr (ih m hm_lt hm_pos) | |
| exact Rat.padicValuation_le_one_iff.mp ((Rat.padicValuation p).map_sub_le hT_int hR) |
I'd prefer .mp and .mpr over .1 and .2 for the two directions of a logical equivalence; this is easier to read.
| refine ⟨_, Rat.coe_int_num_of_den_eq_one ?_⟩ | ||
| by_contra h | ||
| obtain ⟨p, hp, hdvd⟩ := ne_one_iff_exists_prime_dvd.mp h | ||
| exact absurd hdvd (by let : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) |
There was a problem hiding this comment.
| exact absurd hdvd (by let : Fact p.Prime := ⟨hp⟩; exact vonStaudt_sum_den_not_dvd k p hk) | |
| exact (let : Fact p.Prime := ⟨hp⟩; vonStaudt_sum_den_not_dvd k p hk) hdvd |
Rado's proof ("A New Proof of a Theorem of v. Staudt", JLMS 1935) of von Staudt-Clausen theorem. Initially written by AxiomProver (see commit 97a308e) with further golfs with Claude and Codex.